module Clearly::Query::Compose::Range

Methods for composing range queries.

Public Instance Methods

parse_interval(value) click to toggle source

Parse an interval. @param [String] value @return [Array<String>] captures

# File lib/clearly/query/compose/range.rb, line 12
def parse_interval(value)
  range_regex = /(\[|\()(.*),(.*)(\)|\])/i
  matches = value.match(range_regex)
  fail Clearly::Query::QueryArgumentError.new(
           "range string must be in the form (|[.*,.*]|), got '#{value}'") unless matches

  captures = matches.captures
  {
      start_include: captures[0] == '[',
      start_value: captures[1],
      end_value: captures[2],
      end_include: captures[3] == ']'
  }
end
parse_range(hash) click to toggle source

Validate a range. @param [Hash] hash @return [Hash]

# File lib/clearly/query/compose/range.rb, line 30
def parse_range(hash)
  unless hash.is_a?(Hash)
    fail Clearly::Query::QueryArgumentError.new(
             "range filter must be {'from': 'value', 'to': 'value'} " +
                 "or {'interval': '(|[.*,.*]|)'} got '#{hash}'", {hash: hash})

  end

  from = hash[:from]
  to = hash[:to]
  interval = hash[:interval]

  if !from.blank? && !to.blank? && !interval.blank?
    fail Clearly::Query::QueryArgumentError.new(
             "range filter must use either ('from' and 'to') or ('interval'), not both", {hash: hash})
  elsif from.blank? && !to.blank?
    fail Clearly::Query::QueryArgumentError.new(
             "range filter missing 'from'", {hash: hash})
  elsif !from.blank? && to.blank?
    fail Clearly::Query::QueryArgumentError.new(
             "range filter missing 'to'", {hash: hash})
  elsif !from.blank? && !to.blank?
    parse_interval("[#{from},#{to})")
  elsif !interval.blank?
    parse_interval(interval)
  else
    fail Clearly::Query::QueryArgumentError.new(
             "range filter did not contain ('from' and 'to') or ('interval'), got '#{hash}'", {hash: hash})
  end
end

Private Instance Methods

compose_not_range_node(node, value) click to toggle source

Create NOT IN condition using from (inclusive) and to (exclusive). @param [Arel::Nodes::Node, Arel::Attributes::Attribute, String] node @param [Object] value @return [Arel::Nodes::Node] condition

# File lib/clearly/query/compose/range.rb, line 91
def compose_not_range_node(node, value)
  validate_node_or_attribute(node)
  range_info = parse_range(value)

  # build using gt, lt, gteq, lteq
  if range_info[:start_include]
    start_condition = node.lt(range_info[:start_value])
  else
    start_condition = node.lteq(range_info[:start_value])
  end

  if range_info[:end_include]
    end_condition = node.gt(range_info[:end_value])
  else
    end_condition = node.gteq(range_info[:end_value])
  end

  start_condition.or(end_condition)
end
compose_range_node(node, value) click to toggle source

Create IN condition using from (inclusive) and to (exclusive). @param [Arel::Nodes::Node, Arel::Attributes::Attribute, String] node @param [Object] value @return [Arel::Nodes::Node] condition

# File lib/clearly/query/compose/range.rb, line 67
def compose_range_node(node, value)
  validate_node_or_attribute(node)
  range_info = parse_range(value)

  # build using gt, lt, gteq, lteq
  if range_info[:start_include]
    start_condition = node.gteq(range_info[:start_value])
  else
    start_condition = node.gt(range_info[:start_value])
  end

  if range_info[:end_include]
    end_condition = node.lteq(range_info[:end_value])
  else
    end_condition = node.lt(range_info[:end_value])
  end

  start_condition.and(end_condition)
end