module Clearly::Query::Validate

Provides common validations for composing queries.

Public Instance Methods

like_syntax(value, options = {start: false, end: false}) click to toggle source

Create LIKE syntax. @param [String] value @param [Hash] options @return [String]

# File lib/clearly/query/validate.rb, line 181
def like_syntax(value, options = {start: false, end: false})
  "#{options[:start] ? '%' : ''}#{sanitize_like_value(value)}#{options[:end] ? '%' : ''}"
end
sanitize_like_value(value) click to toggle source

Escape wildcards in LIKE value. @param [String] value @return [String] sanitized value

# File lib/clearly/query/validate.rb, line 165
def sanitize_like_value(value)
  value.gsub(/[\\_%\|]/) { |x| "\\#{x}" }
end
sanitize_similar_to_value(value) click to toggle source

Escape meta-characters in SIMILAR TO value. see www.postgresql.org/docs/9.3/static/functions-matching.html @param [String] value @return [String] sanitized value

# File lib/clearly/query/validate.rb, line 173
def sanitize_similar_to_value(value)
  value.gsub(/[\\_%\|\*\+\?\{\}\(\)\[\]]/) { |x| "\\#{x}" }
end
validate_array(value) click to toggle source

Validate an array. @param [Array, Arel::SelectManager] value @raise [FilterArgumentError] if value is not a valid Array. @return [void]

# File lib/clearly/query/validate.rb, line 89
def validate_array(value)
  fail Clearly::Query::QueryArgumentError, "value must be an Array or Arel::SelectManager, got '#{value.class}'" unless value.is_a?(Array) || value.is_a?(Arel::SelectManager)
end
validate_array_items(value) click to toggle source

Validate array items. Do not validate if value is not an Array. @param [Array] value @raise [FilterArgumentError] if Array contents are not valid. @return [void]

# File lib/clearly/query/validate.rb, line 97
def validate_array_items(value)
  # must be a collection of items
  if !value.respond_to?(:each) || !value.respond_to?(:all?) || !value.respond_to?(:any?) || !value.respond_to?(:count)
    fail Clearly::Query::QueryArgumentError, "must be a collection of items, got '#{value.class}'"
  end

  # if there are no items, let it through
  if value.count > 0
    # all items must be the same type (or a subclass). Assume the first item is the correct type.
    type_compare_item = value[0].class
    type_compare = value.all? do |item|
      is_same_class = item.is_a?(type_compare_item)
      item_class = item.class
      is_same_class ? true : (item_class <= Arel::Nodes::Node && type_compare_item <= Arel::Nodes::Node)
    end
    fail Clearly::Query::QueryArgumentError, "array values must be a single consistent type, got '#{value.map { |v| v.class.name }.join(', ')}'" unless type_compare

    # restrict length of strings
    if type_compare_item.is_a?(String)
      max_string_length = 120
      string_length = value.all? { |item| item.size <= max_string_length }
      fail Clearly::Query::QueryArgumentError, "array values that are strings must be '#{max_string_length}' characters or less" unless string_length
    end

    # array contents cannot be Arrays or Hashes
    array_check = value.any? { |item| item.is_a?(Array) }
    fail Clearly::Query::QueryArgumentError, 'array values cannot be arrays' if array_check

    hash_check = value.any? { |item| item.is_a?(Hash) }
    fail Clearly::Query::QueryArgumentError, 'array values cannot be hashes' if hash_check

  end
end
validate_association(model, models_allowed) click to toggle source

Validate model association. @param [ActiveRecord::Base] model @param [Array<ActiveRecord::Base>] models_allowed @return [void]

# File lib/clearly/query/validate.rb, line 21
def validate_association(model, models_allowed)
  validate_model(model)
  validate_not_blank(models_allowed)
  validate_array(models_allowed)

  fail Clearly::Query::QueryArgumentError, "models allowed must be an Array, got '#{models_allowed}'" unless models_allowed.is_a?(Array)
  fail Clearly::Query::QueryArgumentError, "model must be in '#{models_allowed}', got '#{model}'" unless models_allowed.include?(model)
end
validate_boolean(value) click to toggle source

Validate value is a boolean @param [Boolean] value @return [void]

# File lib/clearly/query/validate.rb, line 158
def validate_boolean(value)
  fail Clearly::Query::QueryArgumentError, "value must be a boolean, got '#{value}'" if !value.is_a?(TrueClass) && !value.is_a?(FalseClass)
end
validate_condition(condition) click to toggle source

Validate condition value. @param [Arel::Nodes::Node] condition @raise [FilterArgumentError] if condition is not an Arel::Nodes::Node @return [void]

# File lib/clearly/query/validate.rb, line 50
def validate_condition(condition)
  if !condition.is_a?(Arel::Nodes::Node) && !condition.is_a?(String)
    fail Clearly::Query::QueryArgumentError, "condition must be Arel::Nodes::Node or String, got '#{condition}'"
  end
end
validate_definition(value) click to toggle source

Validate definition specification @param [Hash] value @return [void]

# File lib/clearly/query/validate.rb, line 227
def validate_definition(value)
  validate_not_blank(value)
  validate_hash(value)

  # fields
  validate_not_blank(value[:fields])
  validate_hash(value[:fields])

  validate_not_blank(value[:fields][:valid])
  validate_array(value[:fields][:valid])
  validate_array_items(value[:fields][:valid])

  validate_array(value[:fields][:text])
  validate_array_items(value[:fields][:text])

  validate_not_blank(value[:fields][:mappings])
  validate_array(value[:fields][:mappings])

  value[:fields][:mappings].each do |mapping|
    validate_not_blank(mapping)
    validate_hash(mapping)
    validate_symbol(mapping[:name])
    validate_not_blank(mapping[:value])
  end

  # associations
  validate_spec_association(value[:associations])
end
validate_definition_instance(value) click to toggle source

Validate definition instance @param [Clearly::Query::Definition] value @return [void]

# File lib/clearly/query/validate.rb, line 219
def validate_definition_instance(value)
  validate_not_blank(value)
  fail Clearly::Query::QueryArgumentError, "value must be a model definition, got '#{value.class}'" unless value.is_a?(Clearly::Query::Definition)
end
validate_float(value) click to toggle source

Check that value is a float. @param [Object] value @raise [FilterArgumentError] if value is not a float @return [void]

# File lib/clearly/query/validate.rb, line 204
def validate_float(value)
  validate_not_blank(value)

  filtered = value.to_s.tr('^0-9.', '')
  fail Clearly::Query::QueryArgumentError, "value must be a float, got '#{filtered}'" if filtered != value
  fail Clearly::Query::QueryArgumentError, "value must be a float after conversion, got '#{filtered}'" if filtered != value.to_f

  value_f = filtered.to_f
  fail Clearly::Query::QueryArgumentError, "value must be greater than 0, got '#{value_f}'" if value_f <= 0

end
validate_hash(value) click to toggle source

Validate a hash. @param [Array] value @raise [FilterArgumentError] if value is not a valid Hash. @return [void]

# File lib/clearly/query/validate.rb, line 135
def validate_hash(value)
  fail Clearly::Query::QueryArgumentError, "value must be a Hash, got '#{value}'" unless value.is_a?(Hash)
end
validate_integer(value, min = nil, max = nil) click to toggle source

validate an integer @param [Object] value @param [Integer] min @param [Integer] max @return [void]

# File lib/clearly/query/validate.rb, line 190
def validate_integer(value, min = nil, max = nil)
  validate_not_blank(value)
  fail Clearly::Query::QueryArgumentError, "value must be an integer, got '#{value}'" if value != value.to_i

  value_i = value.to_i

  fail Clearly::Query::QueryArgumentError, "value must be '#{min}' or greater, got '#{value_i}'" if !min.blank? && value_i < min
  fail Clearly::Query::QueryArgumentError, "value must be '#{max}' or less, got '#{value_i}'" if !max.blank? && value_i > max
end
validate_model(model) click to toggle source

Validate model value. @param [ActiveRecord::Base] model @raise [FilterArgumentError] if model is not an ActiveRecord::Base @return [void]

# File lib/clearly/query/validate.rb, line 80
def validate_model(model)
  validate_not_blank(model)
  fail Clearly::Query::QueryArgumentError, "model must be an ActiveRecord::Base, got '#{model.base_class}'" unless model < ActiveRecord::Base
end
validate_name(name, allowed) click to toggle source

Validate name value. @param [Symbol] name @param [Array<Symbol>] allowed @raise [FilterArgumentError] if name is not a symbol in allowed @return [void]

# File lib/clearly/query/validate.rb, line 69
def validate_name(name, allowed)
  validate_not_blank(name)
  fail Clearly::Query::QueryArgumentError, "name must be a symbol, got '#{name}'" unless name.is_a?(Symbol)
  fail Clearly::Query::QueryArgumentError, "allowed must be an Array, got '#{allowed}'" unless allowed.is_a?(Array)
  fail Clearly::Query::QueryArgumentError, "name must be in '#{allowed}', got '#{name}'" unless allowed.include?(name)
end
validate_node_or_attribute(value) click to toggle source

Validate value is a node or attribute @param [Arel::Nodes::Node, Arel::Attributes::Attribute, String] value @return [void]

# File lib/clearly/query/validate.rb, line 59
def validate_node_or_attribute(value)
  check = value.is_a?(Arel::Nodes::Node) || value.is_a?(String) || value.is_a?(Arel::Attributes::Attribute) || value.is_a?(Symbol)
      fail Clearly::Query::QueryArgumentError, "value must be Arel::Nodes::Node or String or Symbol or Arel::Attributes::Attribute, got '#{value}'" unless check
end
validate_not_blank(value) click to toggle source

Validate value is not blank @param [Object] value @return [void]

# File lib/clearly/query/validate.rb, line 151
def validate_not_blank(value)
  fail Clearly::Query::QueryArgumentError, "value must not be empty, got '#{value}'" if value.blank?
end
validate_query(query) click to toggle source

Validate table value. @param [ActiveRecord::Relation] query @raise [FilterArgumentError] if query is not an Arel::Query @return [void]

# File lib/clearly/query/validate.rb, line 42
def validate_query(query)
  fail Clearly::Query::QueryArgumentError, "query must be ActiveRecord::Relation, got '#{query.class}'" unless query.is_a?(ActiveRecord::Relation)
end
validate_spec_association(value) click to toggle source

Validate association specification @param [Array] value @return [void]

# File lib/clearly/query/validate.rb, line 259
def validate_spec_association(value)
  validate_array(value)

  value.each do |association|
    validate_not_blank(association)
    validate_hash(association)
    validate_not_blank(association[:join])
    validate_not_blank(association[:on])
    validate_boolean(association[:available])
    validate_spec_association(association[:associations]) if association.include?(:associations)
  end
end
validate_symbol(value) click to toggle source

Validate a symbol. @param [Symbol] value @raise [FilterArgumentError] if value is not a Symbol. @return [void]

# File lib/clearly/query/validate.rb, line 143
def validate_symbol(value)
  validate_not_blank(value)
  fail Clearly::Query::QueryArgumentError, "value must be a Symbol, got '#{value}'" unless value.is_a?(Symbol)
end
validate_table(table) click to toggle source

Validate table value. @param [Arel::Table] table @raise [FilterArgumentError] if table is not an Arel::Table @return [void]

# File lib/clearly/query/validate.rb, line 34
def validate_table(table)
  fail Clearly::Query::QueryArgumentError, "table must be Arel::Table, got '#{table.class}'" unless table.is_a?(Arel::Table)
end
validate_table_column(table, column_name, allowed) click to toggle source

Validate table and column values. @param [Arel::Table] table @param [Symbol] column_name @param [Array<Symbol>] allowed @return [void]

# File lib/clearly/query/validate.rb, line 12
def validate_table_column(table, column_name, allowed)
  validate_table(table)
  validate_name(column_name, allowed)
end