lib/axiom/relation/operation/sorted/direction.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: utf-8

module Axiom
  class Relation
    module Operation
      class Sorted

        # Abstract base class for attribute sorting
        class Direction
          extend Aliasable
          include AbstractType
          include Equalizer.new(:attribute)

          inheritable_alias(:== => :eql?)

          # The attribute to sort on
          #
          # @return [Attribute]
          #
          # @api private
          attr_reader :attribute

          # Initialize a Direction
          #
          # @param [Attribute] attribute
          #   the attribute to sort on
          #
          # @return [undefined]
          #
          # @api private
          def initialize(attribute)
            @attribute = attribute
          end

          # Return the attribute name
          #
          # @example
          #   direction.name  # => :id
          #
          # @return [Symbol]
          #
          # @api public
          def name
            attribute.name
          end

          # Compare the left and right Tuple attribute values
          #
          # @example
          #   comparison = direction.call(left, right)
          #
          # @param [Tuple] left
          # @param [Tuple] right
          #
          # @return [-1]
          #   returned if the left should be sorted before the right
          #
          # @return [0]
          #   returned if the left and right are equal
          #
          # @return [1]
          #   returned if the left should be sorted after the right
          #
          # @api public
          def call(left, right)
            self.class.call(attribute.call(left), attribute.call(right))
          end

          # Rename the contained attribute with the provided aliases
          #
          # @example
          #   renamed = direction.rename(aliases)
          #
          # @param [Algebra::Rename::Aliases] aliases
          #   the old and new attributes
          #
          # @return [self]
          #   if the attribute is not renamed
          # @return [Direction]
          #   if the attribute is renamed
          #
          # @api public
          def rename(aliases)
            renamed = aliases[attribute]
            renamed.equal?(attribute) ? self : self.class.new(renamed)
          end

          # Return the reverse Direction
          #
          # @example
          #   reversed = direction.reverse
          #
          # @return [Direction]
          #
          # @api public
          def reverse
            self.class.reverse.new(attribute)
          end

          # Coerce an object into a Direction
          #
          # @param [Attribute, Direction] object
          #   the object to coerce
          #
          # @return [Direction]
          #
          # @api private
          def self.coerce(object)
            object.kind_of?(Direction) ? object : new(Attribute.coerce(object))
          end

        end # class Direction

        # Represent an attribute sorted ascending
        class Ascending < Direction

          # Return the reversed direction class
          #
          # @return [Class<Descending>]
          #
          # @api private
          def self.reverse
            Descending
          end

          # Compare the left and right value
          #
          # @param [Comparable] left
          # @param [Comparable] right
          #
          # @return [-1]
          #   returned if the left should be sorted before the right
          #
          # @return [0]
          #   returned if the left and right are equal
          #
          # @return [1]
          #   returned if the left should be sorted after the right
          #
          # @api private
          def self.call(left, right)
            left <=> right || (1 if left.nil?) || (-1 if right.nil?)
          end

        end # class Ascending

        # Represent an attribute sorted descending
        class Descending < Direction

          # Return the reversed direction class
          #
          # @return [Class<Ascending>]
          #
          # @api private
          def self.reverse
            Ascending
          end

          # Compare the left and right value
          #
          # @param [Comparable] left
          # @param [Comparable] right
          #
          # @return [-1]
          #   returned if the left should be sorted after the right
          #
          # @return [0]
          #   returned if the right and left are equal
          #
          # @return [1]
          #   returned if the left should be sorted before the right
          #
          # @api private
          def self.call(left, right)
            right <=> left || (1 if right.nil?) || (-1 if left.nil?)
          end

        end # class Descending
      end # class Sorted
    end # module Operation
  end # class Relation
end # module Axiom