Class: DynamicScope::Query

Inherits:
Object
  • Object
show all
Includes:
QueryHelpers
Defined in:
lib/dynamic_scope/query.rb

Defined Under Namespace

Classes: InvalidValue, MissingRequiredKey, UnallowedOperator, UnsupportedType

Constant Summary collapse

REQUIRED_KEYS =
[:key, :operator, :value].freeze
SUPPORTED_TYPES =
[:integer, :string, :enum, :year, :month, :date, :date_future, :datetime, :boolean].freeze
OPERATORS =
{
  integer:     [:eq, :not_eq, :gteq, :lteq, :in, :not_in],
  string:      [:matches, :does_not_match, :begins_with, :ends_with, :eq, :not_eq],
  enum:        [:eq, :not_eq, :in, :not_in],
  year:        [:eq, :gteq, :lteq],
  month:       [:eq, :gteq, :lteq, :eq_since, :gteq_since, :lteq_since],
  date:        [:eq, :gteq, :lteq],
  date_future: [:eq, :gteq, :lteq],
  datetime:    [:eq, :gteq, :lteq],
  boolean:     [:eq, :not_eq]
}.freeze
NEGATIVE_OPERATORS =
[:not_eq, :does_not_match, :not_in].freeze

Constants included from QueryHelpers

DynamicScope::QueryHelpers::TRUTHY_VALUES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from QueryHelpers

#query_param_falsy?, #query_param_truthy?

Constructor Details

#initialize(_scope, _query, _config) ⇒ Query

Returns a new instance of Query.



38
39
40
41
42
43
44
45
# File 'lib/dynamic_scope/query.rb', line 38

def initialize(_scope, _query, _config)
  @query = _query
  @config = _config

  check_query_for_missing_keys!

  @scope = query_config[:relation].present? ? _scope.joins(query_config[:relation]) : _scope
end

Instance Attribute Details

#configObject

Returns the value of attribute config.



36
37
38
# File 'lib/dynamic_scope/query.rb', line 36

def config
  @config
end

#queryObject

Returns the value of attribute query.



36
37
38
# File 'lib/dynamic_scope/query.rb', line 36

def query
  @query
end

Instance Method Details

#arel_queryObject



51
52
53
54
55
56
57
58
# File 'lib/dynamic_scope/query.rb', line 51

def arel_query
  arel = scope_klass.arel_table[attribute_name]
  aq = arel.send(operator_for_arel, value_for_arel)
  if query_param_truthy?(@query[:null] || query_config[:null]) and NEGATIVE_OPERATORS.include?(operator)
    aq = aq.or(arel.eq(nil))
  end
  aq
end

#attribute_nameObject



78
79
80
# File 'lib/dynamic_scope/query.rb', line 78

def attribute_name
  (query_config[:attribute_name] || query_key).to_sym
end

#operatorObject



69
70
71
72
73
74
75
76
# File 'lib/dynamic_scope/query.rb', line 69

def operator
  oper = @query[:operator].to_sym
  if OPERATORS[type].include?(oper)
    oper
  else
    raise UnallowedOperator.new(@query), "Query (#{@query}) has unallowed operator: #{oper}"
  end
end

#operator_for_arelObject



154
155
156
157
158
159
# File 'lib/dynamic_scope/query.rb', line 154

def operator_for_arel
  {
    begins_with: :matches,
    ends_with: :matches
  }[operator] || operator
end

#query_configObject



47
48
49
# File 'lib/dynamic_scope/query.rb', line 47

def query_config
  @config[query_key]
end

#scopeObject



60
61
62
63
64
65
66
67
# File 'lib/dynamic_scope/query.rb', line 60

def scope
  return nil if value.blank?
  if custom_scope?
    scope_klass.send(custom_scope_name, operator, value)
  else
    @scope.where(arel_query)
  end
end

#scope_klassObject



145
146
147
148
149
150
151
152
# File 'lib/dynamic_scope/query.rb', line 145

def scope_klass
  @scope_klass ||=
    if query_config[:relation]
      resolve_relation(@scope.klass, query_config[:relation])
    else
      @scope.klass
    end
end

#typeObject



137
138
139
140
141
142
143
# File 'lib/dynamic_scope/query.rb', line 137

def type
  t = query_config[:type].to_sym
  unless SUPPORTED_TYPES.include?(t)
    raise UnsupportedType.new(query_config), "Config (#{query_config}) has unsupported type: #{t}"
  end
  t
end

#valueObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/dynamic_scope/query.rb', line 82

def value
  val = query_config[:value].is_a?(Proc) ? query_config[:value].call(@query[:value]) : @query[:value]
  return nil if val.nil? || val.to_s.strip.length == 0
  case type
  when :string
    val.to_s
  when :integer
    val.to_s.include?(',') ? val.split(',').map(&:to_i) : val.to_i
  when :enum
    val.split(',').each do |v|
      unless allowed_values.include?(v)
        raise InvalidValue.new(@query), "Query (#{@query}) has invalid value: #{v}"
      end
    end
    val
  when :year
    val.to_s
  when :month
    val.to_s
  when :date, :date_future
    Date.parse(val.to_s)
  when :datetime
    DateTime.parse(val.to_s)
  when :boolean
    if ['1', 'true', true].include?(val)
      true
    elsif ['0', 'false', false].include?(val)
      false
    end
  end
end

#value_for_arelObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/dynamic_scope/query.rb', line 114

def value_for_arel
  case type
  when :string
    if [:matches, :does_not_match].include?(operator)
      "%#{value}%"
    elsif [:begins_with].include?(operator)
      "#{value}%"
    elsif [:ends_with].include?(operator)
      "%#{value}"
    else
      value
    end
  when :enum
    if [:in, :not_in].include?(operator)
      value.split(',')
    else
      value
    end
  else
    value
  end
end