little-bobby-tables/elasticfusion

View on GitHub
lib/elasticfusion/search/query/visitors/polyadic_tree.rb

Summary

Maintainability
A
45 mins
Test Coverage
# frozen_string_literal: true
require 'elasticfusion/search/query/visitor'
require 'elasticfusion/search/query/ast'

module Elasticfusion
  module Search
    module Query
      module Visitors
        # +PolyadicTree+ is a base class for visitors that accept
        # more than two operands for logical expressions.
        # It converts a binary tree into multi-way tree, replacing all
        # +Expression+ nodes with +PolyadicExpression+ nodes.
        #
        # Given an AST:
        #
        #    and
        #  /     \
        # A      and
        #      /     \
        #     B      and
        #          /     \
        #         C       or
        #               /   \
        #              D     E
        #
        # A polyadic representation would be:
        #
        #      and
        #  /  /   \   \
        # A  B    C   or
        #            /  \
        #           D    E

        class PolyadicTree < Visitor
          def accept(node)
            super(rewrite(node))
          end

          def rewrite(node, parent: nil)
            case node
            when NegatedClause
              node.body = rewrite(node.body)
            when Expression
              flattened = [rewrite(node.left, parent: node),
                           rewrite(node.right, parent: node)].flatten

              if parent && node.op && node.op == parent.op
                return flattened
              else
                return PolyadicExpression.new(node.op, flattened)
              end
            end
            node
          end
        end
      end
    end
  end
end