Module: ElasticsearchRecord::Relation::QueryMethods

Defined in:
lib/elasticsearch_record/relation/query_methods.rb

Instance Method Summary collapse

Instance Method Details

#aggregate(*args) ⇒ Object Also known as: aggs

create or add an aggregation to the query.

Examples:

aggregate(:total, { sum: {field: :amount})


65
66
67
68
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 65

def aggregate(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.aggregate!(*args)
end

#aggregate!(opts, *rest) ⇒ Object

:nodoc:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 72

def aggregate!(opts, *rest) # :nodoc:
  case opts
  when Symbol, String
    self.aggs_clause += build_query_clause(opts, rest)
  when Hash
    opts.each do |key, value|
      self.aggs_clause += build_query_clause(key, value)
    end
  else
    raise ArgumentError, "Unsupported argument type for aggregate: #{opts}"
  end

  self
end

#configure(*args) ⇒ Object

sets or overwrites additional arguments for the query (not the :query-node, the whole query). You can also force a overwrite of previously defined arguments, like +size+ or +from+. This is useful to force remove of keys.

Examples:

# adds {refresh true} to the query
configure(:refresh, true)

# overwrites or sets {from: 50} but removes the :sort key
configure({from: 50, sort: nil})

Parameters:

  • args (Array)


41
42
43
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 41

def configure(*args)
  spawn.configure!(*args)
end

#configure!(*args) ⇒ Object

same like +#configure!+, but on the same relation (no spawn)



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 46

def configure!(*args)
  check_if_method_has_arguments!(__callee__, args)

  if args.length == 1 && args.first.is_a?(Hash)
    self.configure_value = self.configure_value.merge(args[0])
  elsif args.length == 2 && args[0] == :__claim__
    tmp = self.configure_value[:__claim__] || []
    tmp << args[1]
    self.configure_value = self.configure_value.merge(:__claim__ => tmp)
  elsif args.length == 2
    self.configure_value = self.configure_value.merge(args[0] => args[1])
  end

  self
end

#filter(*args) ⇒ Object

adds a +filter+ clause.

Examples:

filter({terms: ...})


104
105
106
107
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 104

def filter(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.filter!(*args)
end

#filter!(opts, *rest) ⇒ Object

:nodoc:



109
110
111
112
113
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 109

def filter!(opts, *rest) # :nodoc:
  set_default_kind!
  self.query_clause += build_query_clause(:filter, opts, rest)
  self
end

#joinsObject

unsupported method

Raises:

  • (ActiveRecord::StatementInvalid)


6
7
8
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 6

def joins(*)
  raise ActiveRecord::StatementInvalid, 'Unsupported method "joins"'
end

#kind(value) ⇒ Object

sets or overwrites the query kind (e.g. compound queries -> :bool, :boosting, :constant_score, ...). Also other query kinds like :intervals, :match, ... are allowed. Alternatively the +#query+-method can also be used to provide a kind with arguments.

Parameters:

  • value (String, Symbol)
    • the kind


19
20
21
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 19

def kind(value)
  spawn.kind!(value)
end

#kind!(value) ⇒ Object

same like +#kind+, but on the same relation (no spawn)



24
25
26
27
28
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 24

def kind!(value)
  # :nodoc:
  self.kind_value = value
  self
end

#must(*args) ⇒ Object

adds a +must+ clause.

Examples:

must({terms: ...})


132
133
134
135
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 132

def must(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.must!(*args)
end

#must!(opts, *rest) ⇒ Object

:nodoc:



137
138
139
140
141
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 137

def must!(opts, *rest) # :nodoc:
  set_default_kind!
  self.query_clause += build_query_clause(:must, opts, rest)
  self
end

#must_not(*args) ⇒ Object

adds a +must_not+ clause.

Examples:

filter({terms: ...})


118
119
120
121
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 118

def must_not(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.must_not!(*args)
end

#must_not!(opts, *rest) ⇒ Object

:nodoc:



123
124
125
126
127
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 123

def must_not!(opts, *rest) # :nodoc:
  set_default_kind!
  self.query_clause += build_query_clause(:must_not, opts, rest)
  self
end

#or!(other) ⇒ Object



241
242
243
244
245
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 241

def or!(other)
  self.query_clause = self.query_clause.or(other.query_clause)

  super(other)
end

#query(*args) ⇒ Object

add a whole query 'node' to the query.

Examples:

query(:bool, {filter: ...})


90
91
92
93
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 90

def query(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.query!(*args)
end

#query!(kind, opts, *rest) ⇒ Object

:nodoc:



95
96
97
98
99
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 95

def query!(kind, opts, *rest) # :nodoc:
  kind!(kind)
  self.query_clause += build_query_clause(opts.keys[0], opts.values[0], rest)
  self
end

#should(*args) ⇒ Object

adds a +should+ clause.

Examples:

should({terms: ...})


146
147
148
149
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 146

def should(*args)
  check_if_method_has_arguments!(__callee__, args)
  spawn.should!(*args)
end

#should!(opts, *rest) ⇒ Object

:nodoc:



151
152
153
154
155
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 151

def should!(opts, *rest) # :nodoc:
  set_default_kind!
  self.query_clause += build_query_clause(:should, opts, rest)
  self
end

#unscope!(*args) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 247

def unscope!(*args)
  # :nodoc:
  self.unscope_values += args

  args.each do |scope|
    case scope
    when Symbol
      unless _valid_unscoping_values.include?(scope)
        raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{_valid_unscoping_values.to_a.join(", :")}."
      end
      assert_mutability!
      @values.delete(scope)
    when Hash
      scope.each do |key, target_value|
        target_query_clause = build_query_clause(key, target_value)
        self.query_clause   -= target_query_clause
      end
    else
      raise ArgumentError, "Unrecognized scoping: #{args.inspect}. Use .unscope(where: :attribute_name) or .unscope(:order), for example."
    end
  end

  self
end

#where(*args) ⇒ Object

creates a condition on the relation. There are several possibilities to call this method.

Examples:

# create a simple 'term' condition on the query[:filter] param
  where({name: 'hans'})
  > query[:filter] << { term: { name: 'hans' } }

# create a simple 'terms' condition on the query[:filter] param
  where({name: ['hans','peter']})
  > query[:filter] << { terms: { name: ['hans','peter'] } }

  where(:must_not, term: {name: 'horst'})
  where(:query_string, "(new york OR dublin)", fields: ['name','description'])

# nested array
where([ [:filter, {...}], [:must_not, {...}]])


173
174
175
176
177
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 173

def where(*args)
  return none if args[0] == :none

  super
end

#where!(opts, *rest) ⇒ Object

:nodoc:



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/elasticsearch_record/relation/query_methods.rb', line 179

def where!(opts, *rest) # :nodoc:
  case opts
    # check the first provided parameter +opts+ and validate, if this is an alias for "must, must_not, should or filter"
    # if true, we expect the rest[0] to be a hash.
    # For this correlation we forward this as RAW-data without check & manipulation
  when Symbol
    case opts
    when :filter, :must, :must_not, :should
      send("#{opts}!", *rest)
    else
      raise ArgumentError, "Unsupported argument type for where: #{opts}"
    end
  when Array
    # check if this is a nested array of multiple [<kind>,<data>]
    if opts[0].is_a?(Array)
      opts.each { |item|
        where!(*item)
      }
    else
      where!(*opts, *rest)
    end
  when String
    # fallback to ActiveRecords +#where_clause+
    # currently NOT supported
    super(opts, rest)
  else
    # hash -> {name: 'hans'}
    # protects against forwarding params directly to where ...
    # User.where(params) <- will never work
    # User.where(params.permit(:user)) <- ok
    opts = sanitize_forbidden_attributes(opts)

    # resolve possible aliases
    opts = opts.transform_keys do |key|
      key = key.to_s
      klass.attribute_aliases[key] || key
    end

    # check if we have keys without Elasticsearch fields
    if (invalid = (opts.keys - klass.searchable_column_names)).present?
      raise(ActiveRecord::UnknownAttributeReference,
            "Unable to build query with unknown searchable attributes: #{invalid.map(&:inspect).join(", ")}. " \
          "If you want to build a custom query you should use one of those methods: 'filter, must, must_not, should'. " \
          "#{klass.name}.filter('#{invalid[0]}' => '...')"
      )
    end

    # force set default kind, if not previously set
    set_default_kind!

    # builds predicates from opts (transforms this in a more unreadable way but is required for nested assignment & binds ...)
    parts = opts.map do |key,value|
      # builds and returns a new Arel Node from provided key/value pair
      predicate_builder[key,value]
    end

    self.where_clause += ::ActiveRecord::Relation::WhereClause.new(parts)
  end

  self
end