module Veritas class Optimizer module Algebra # Abstract base class representing Restriction optimizations class Restriction < Relation::Operation::Unary # The optimized predicate # # @return [Expression] # # @api private attr_reader :predicate # Initialize an Restriction optimizer # # @return [undefined] # # @api private def initialize(*) super @predicate = self.class.optimize_predicate(operation.predicate) end private # Wrap the operand's operand in a Restriction # # @return [Restriction] # # @api private def wrap_operand operation.class.new(operand.operand, predicate).optimize end # Optimize the predicate if possible # # @param [Expression] predicate # # @return [Expression] # # @api private def self.optimize_predicate(predicate) predicate.respond_to?(:optimize) ? predicate.optimize : predicate end # Optimize when the predicate is true class TruePredicate < self # Test if the predicate is true # # @return [Boolean] # # @api private def optimizable? predicate.equal?(Veritas::Logic::Proposition::True.instance) end # A Restriction with a true predicate is a noop # # @return [Relation] # # @api private def optimize operand end end # class TruePredicate # Optimize when the predicate is false class FalsePredicate < self # Test if the predicate is false # # @return [Boolean] # # @api private def optimizable? predicate.equal?(Veritas::Logic::Proposition::False.instance) end # A Restriction with a false predicate matches nothing # # @return [Relation] # # @api private def optimize Veritas::Relation::Empty.new(operation.header) end end # class FalsePredicate # Optimize when the operand is a Restriction class RestrictionOperand < self # Test if the operand is a Restriction # # @return [Boolean] # # @api private def optimizable? operand.kind_of?(operation.class) end # Flatten nested Restrictions into a single Restriction # # @return [Projection] # # @api private def optimize operation.class.new(operand.operand, optimized_predicate).optimize end private # Join the operand and operation predicates and optimize them # # @return [Expression] # # @api private def optimized_predicate Veritas::Logic::Connective::Conjunction.new(operand.predicate, predicate).optimize end end # class RestrictionOperand # Optimize when the operand is a Set class SetOperand < self # Test if the operand is a Restriction # # @return [Boolean] # # @api private def optimizable? operand.kind_of?(Veritas::Relation::Operation::Set) end # Wrap each operand in the Set in a Restriction # # @return [Set] # # @api private def optimize operand.class.new(wrap_left, wrap_right).optimize end private # Utility method to wrap the left operand in a Restriction # # @return [Restriction] # # @api private def wrap_left operation.class.new(operand.left, predicate).optimize end # Utility method to wrap the right operand in a Restriction # # @return [Restriction] # # @api private def wrap_right operation.class.new(operand.right, predicate).optimize end end # class SetOperand # Optimize when the operand is a Reverse class ReverseOperand < self # Test if the operand is a Reverse # # @return [Boolean] # # @api private def optimizable? operand.kind_of?(Veritas::Relation::Operation::Reverse) end # Wrap the Restriction in a Reverse # # @return [Reverse] # # @api private def optimize operand.class.new(wrap_operand).optimize end end # class ReverseOperand # Optimize when the operand is an Order class OrderOperand < self # Test if the operand is an Order # # @return [Boolean] # # @api private def optimizable? operand.kind_of?(Veritas::Relation::Operation::Order) end # Wrap the Restriction in an Order # # @return [Order] # # @api private def optimize operand = self.operand operand.class.new(wrap_operand, operand.directions).optimize end end # class OrderOperand # Optimize when operand is optimizable class UnoptimizedOperand < self # Test if the operand is unoptimized # # @return [Boolean] # # @api private def optimizable? operation = self.operation !operand.equal?(operation.operand) || !predicate.equal?(operation.predicate) end # Return a Restriction with an optimized operand # # @return [Rename] # # @api private def optimize operation.class.new(operand, predicate).optimize end end # class UnoptimizedOperand Veritas::Algebra::Restriction.optimizer = chain( TruePredicate, FalsePredicate, RestrictionOperand, SetOperand, ReverseOperand, OrderOperand, EmptyOperand, MaterializedOperand, UnoptimizedOperand ) end # class Restriction end # module Algebra end # class Optimizer end # module Veritas