ruby-odata/odata

View on GitHub
lib/odata/query.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module OData
  # OData::Query provides the query interface for requesting Entities matching
  # specific criteria from an OData::EntitySet. This class should not be
  # instantiated directly, but can be. Normally you will access a Query by
  # first asking for one from the OData::EntitySet you want to query.
  class Query
    # Create a new Query for the provided EntitySet
    # @param entity_set [OData::EntitySet]
    def initialize(entity_set)
      @entity_set = entity_set
      setup_empty_criteria_set
    end

    # Instantiates an OData::Query::Criteria for the named property.
    # @param property [to_s]
    def [](property)
      property_instance = @entity_set.new_entity.get_property(property)
      property_instance = property if property_instance.nil?
      OData::Query::Criteria.new(property: property_instance)
    end

    # Adds a filter criteria to the query.
    # For filter syntax see https://msdn.microsoft.com/en-us/library/gg309461.aspx
    # Syntax:
    #   Property Operator Value
    #
    # For example:
    #   Name eq 'Customer Service'
    #
    # Operators:
    # eq, ne, gt, ge, lt, le, and, or, not
    #
    # Value
    #  can be 'null', can use single quotes
    # @param criteria
    def where(criteria)
      criteria_set[:filter] << criteria
      self
    end

    # Adds a filter criteria to the query with 'and' logical operator.
    # @param criteria
    #def and(criteria)
    #
    #end

    # Adds a filter criteria to the query with 'or' logical operator.
    # @param criteria
    #def or(criteria)
    #
    #end

    # Specify properties to order the result by.
    # Can use 'desc' like 'Name desc'
    # @param properties [Array<Symbol>]
    # @return [self]
    def order_by(*properties)
      criteria_set[:orderby] += properties
      self
    end

    # Specify associations to expand in the result.
    # @param associations [Array<Symbol>]
    # @return [self]
    def expand(*associations)
      criteria_set[:expand] += associations
      self
    end

    # Specify properties to select within the result.
    # @param properties [Array<Symbol>]
    # @return [self]
    def select(*properties)
      criteria_set[:select] += properties
      self
    end

    # Add skip criteria to query.
    # @param value [to_i]
    # @return [self]
    def skip(value)
      criteria_set[:skip] = value.to_i
      self
    end

    # Add limit criteria to query.
    # @param value [to_i]
    # @return [self]
    def limit(value)
      criteria_set[:top] = value.to_i
      self
    end

    # Add inline count criteria to query.
    # Not Supported in CRM2011
    # @return [self]
    def include_count
      criteria_set[:inline_count] = true
      self
    end

    # Convert Query to string.
    # @return [String]
    def to_s
      [entity_set.name, assemble_criteria].compact.join('?')
    end

    # Execute the query.
    # @return [OData::Query::Result]
    def execute
      response = entity_set.service.execute(self.to_s)
      OData::Query::Result.new(self, response)
    end

    # Executes the query to get a count of entities.
    # @return [Integer]
    def count
      url_chunk = "#{entity_set.name}/$count?#{assemble_criteria}"
      entity_set.service.execute(url_chunk).body.to_i
    end

    # Checks whether a query will return any results by calling #count
    # @return [Boolean]
    def empty?
      self.count == 0
    end

    # The EntitySet for this query.
    # @return [OData::EntitySet]
    # @api private
    def entity_set
      @entity_set
    end

    private

    def criteria_set
      @criteria_set
    end

    def setup_empty_criteria_set
      @criteria_set = {
          filter:       [],
          select:       [],
          expand:       [],
          orderby:      [],
          skip:         0,
          top:          0,
          inline_count: false
      }
    end

    def assemble_criteria
      criteria = [
        filter_criteria,
        list_criteria(:orderby),
        list_criteria(:expand),
        list_criteria(:select),
        inline_count_criteria,
        paging_criteria(:skip),
        paging_criteria(:top)
      ].compact!

      criteria.empty? ? nil : criteria.join('&')
    end

    def filter_criteria
      return nil if criteria_set[:filter].empty?
      filters = criteria_set[:filter].collect {|criteria| criteria.to_s}
      "$filter=#{filters.join(' and ')}"
    end

    def list_criteria(name)
      criteria_set[name].empty? ? nil : "$#{name}=#{criteria_set[name].join(',')}"
    end

    # inlinecount not supported by Microsoft CRM 2011
    def inline_count_criteria
      criteria_set[:inline_count] ? '$inlinecount=allpages' : nil
    end

    def paging_criteria(name)
      criteria_set[name] == 0 ? nil : "$#{name}=#{criteria_set[name]}"
    end
  end
end