Module: Clearly::Query::Validate

Overview

Provides common validations for composing queries.

Instance Method Summary collapse

Instance Method Details

#like_syntax(value, options = {start: false, end: false}) ⇒ String

Create LIKE syntax.

Parameters:

  • value (String)
  • options (Hash) (defaults to: {start: false, end: false})

Returns:

  • (String)

181
182
183
# 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) ⇒ String

Escape wildcards in LIKE value.

Parameters:

  • value (String)

Returns:

  • (String)

    sanitized value


165
166
167
# File 'lib/clearly/query/validate.rb', line 165

def sanitize_like_value(value)
  value.gsub(/[\\_%\|]/) { |x| "\\#{x}" }
end

#sanitize_similar_to_value(value) ⇒ String

Escape meta-characters in SIMILAR TO value. see www.postgresql.org/docs/9.3/static/functions-matching.html

Parameters:

  • value (String)

Returns:

  • (String)

    sanitized value


173
174
175
# File 'lib/clearly/query/validate.rb', line 173

def sanitize_similar_to_value(value)
  value.gsub(/[\\_%\|\*\+\?\{\}\(\)\[\]]/) { |x| "\\#{x}" }
end

#validate_array(value) ⇒ void

This method returns an undefined value.

Validate an array.

Parameters:

  • value (Array, Arel::SelectManager)

Raises:

  • (FilterArgumentError)

    if value is not a valid Array.


89
90
91
# 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) ⇒ void

This method returns an undefined value.

Validate array items. Do not validate if value is not an Array.

Parameters:

  • value (Array)

Raises:

  • (FilterArgumentError)

    if Array contents are not valid.


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# 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) ⇒ void

This method returns an undefined value.

Validate model association.

Parameters:

  • model (ActiveRecord::Base)
  • models_allowed (Array<ActiveRecord::Base>)

21
22
23
24
25
26
27
28
# 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) ⇒ void

This method returns an undefined value.

Validate value is a boolean

Parameters:

  • value (Boolean)

158
159
160
# 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) ⇒ void

This method returns an undefined value.

Validate condition value.

Parameters:

  • condition (Arel::Nodes::Node)

Raises:

  • (FilterArgumentError)

    if condition is not an Arel::Nodes::Node


50
51
52
53
54
# 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) ⇒ void

This method returns an undefined value.

Validate definition specification

Parameters:

  • value (Hash)

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# 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) ⇒ void

This method returns an undefined value.

Validate definition instance

Parameters:


219
220
221
222
# 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) ⇒ void

This method returns an undefined value.

Check that value is a float.

Parameters:

  • value (Object)

Raises:

  • (FilterArgumentError)

    if value is not a float


204
205
206
207
208
209
210
211
212
213
214
# 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) ⇒ void

This method returns an undefined value.

Validate a hash.

Parameters:

  • value (Array)

Raises:

  • (FilterArgumentError)

    if value is not a valid Hash.


135
136
137
# 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) ⇒ void

This method returns an undefined value.

validate an integer

Parameters:

  • value (Object)
  • min (Integer) (defaults to: nil)
  • max (Integer) (defaults to: nil)

190
191
192
193
194
195
196
197
198
# 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) ⇒ void

This method returns an undefined value.

Validate model value.

Parameters:

  • model (ActiveRecord::Base)

Raises:

  • (FilterArgumentError)

    if model is not an ActiveRecord::Base


80
81
82
83
# 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) ⇒ void

This method returns an undefined value.

Validate name value.

Parameters:

  • name (Symbol)
  • allowed (Array<Symbol>)

Raises:

  • (FilterArgumentError)

    if name is not a symbol in allowed


69
70
71
72
73
74
# 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) ⇒ void

This method returns an undefined value.

Validate value is a node or attribute

Parameters:

  • value (Arel::Nodes::Node, Arel::Attributes::Attribute, String)

59
60
61
62
# 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) ⇒ void

This method returns an undefined value.

Validate value is not blank

Parameters:

  • value (Object)

151
152
153
# 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) ⇒ void

This method returns an undefined value.

Validate table value.

Parameters:

  • query (ActiveRecord::Relation)

Raises:

  • (FilterArgumentError)

    if query is not an Arel::Query


42
43
44
# 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) ⇒ void

This method returns an undefined value.

Validate association specification

Parameters:

  • value (Array)

259
260
261
262
263
264
265
266
267
268
269
270
# 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) ⇒ void

This method returns an undefined value.

Validate a symbol.

Parameters:

  • value (Symbol)

Raises:

  • (FilterArgumentError)

    if value is not a Symbol.


143
144
145
146
# 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) ⇒ void

This method returns an undefined value.

Validate table value.

Parameters:

  • table (Arel::Table)

Raises:

  • (FilterArgumentError)

    if table is not an Arel::Table


34
35
36
# 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) ⇒ void

This method returns an undefined value.

Validate table and column values.

Parameters:

  • table (Arel::Table)
  • column_name (Symbol)
  • allowed (Array<Symbol>)

12
13
14
15
# 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