Module: Motor::ApiQuery::Filter

Defined in:
lib/motor/api_query/filter.rb

Constant Summary collapse

LIKE_FILTER_VALUE_REGEXP =
/\A%?(.*?)%?\z/.freeze
DISTINCT_RESTRICTED_COLUMN_TYPES =
%i[json point].freeze

Class Method Summary collapse

Class Method Details

.call(rel, params) ⇒ Object



11
12
13
14
15
16
17
18
19
20
# File 'lib/motor/api_query/filter.rb', line 11

def call(rel, params)
  return rel if params.blank?

  normalized_params = normalize_params(Array.wrap(params))

  rel = rel.filter(normalized_params)
  rel = rel.distinct if can_apply_distinct?(rel)

  rel
end

.can_apply_distinct?(rel) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
57
58
# File 'lib/motor/api_query/filter.rb', line 54

def can_apply_distinct?(rel)
  rel.columns.none? do |column|
    DISTINCT_RESTRICTED_COLUMN_TYPES.include?(column.type)
  end
end

.normalize_action(action, value) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/motor/api_query/filter.rb', line 60

def normalize_action(action, value)
  case action
  when 'includes'
    ['contains', value]
  when 'contains'
    ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '%\1%')]
  when 'starts_with'
    ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '\1%')]
  when 'ends_with'
    ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '%\1')]
  when 'eqnull'
    ['eq', nil]
  when 'neqnull'
    ['neq', nil]
  else
    [action, value]
  end
end

.normalize_filter_hash(hash) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/motor/api_query/filter.rb', line 39

def normalize_filter_hash(hash)
  hash.each_with_object({}) do |(action, value), acc|
    new_action, new_value =
      if value.is_a?(Hash)
        [action, normalize_filter_hash(value)]
      else
        normalize_action(action, value)
      end

    acc[new_action] = new_value

    acc
  end
end

.normalize_params(params) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/motor/api_query/filter.rb', line 22

def normalize_params(params)
  params.map do |item|
    next item if item.is_a?(String)
    next normalize_params(item) if item.is_a?(Array)

    item = item.to_unsafe_h if item.respond_to?(:to_unsafe_h)

    item.transform_values do |filter|
      if filter.is_a?(Hash)
        normalize_filter_hash(filter)
      else
        filter
      end
    end
  end.split('OR').product(['OR']).flatten(1)[0...-1]
end