class CustomAttributes::SearchQuery

Builds a query in elastic search DSL

Attributes

customizable[RW]
defaults[RW]
field_list[RW]
filter_by[RW]
filter_by_delimiter[RW]
filter_or[RW]
filter_or_delimiter[RW]
match_any[RW]
page[RW]
per_page[RW]
query[RW]
sort_by[RW]

Public Instance Methods

build() click to toggle source
# File lib/custom_attributes/search_query.rb, line 8
def build
  {
    query: subquery,
    from: from,
    size: per_page,
    sort: sort_hash_to_array
  }
end
default_fields() click to toggle source
# File lib/custom_attributes/search_query.rb, line 69
def default_fields
  default_fields = {
    custom_fields: Hash[customizable.available_custom_fields
                                     .select { |cf| cf.searchable == true }
                                     .map { |cf| [cf.slug.to_sym, {}] }]
  }

  if customizable.present?
    default_fields[:fields] = Hash[
      customizable.class.default_fields.map { |f| [f.to_sym, {}] }
    ]
  end

  default_fields
end
from() click to toggle source
# File lib/custom_attributes/search_query.rb, line 17
def from
  (page - 1) * per_page
end
match_any?() click to toggle source
# File lib/custom_attributes/search_query.rb, line 65
def match_any?
  @match_any
end

Private Instance Methods

collect_queries() click to toggle source
# File lib/custom_attributes/search_query.rb, line 112
def collect_queries
  # build field specific queries
  queries = model_field_queries + custom_value_queries

  # if there are not field specific queries, match all fields
  if queries.count.zero?
    if query == '*'
      { match_all: {} }
    else
      { match: { _all: query } }
    end
  else
    queries
  end
end
custom_query_scaffold(query, field_slug, filter = false) click to toggle source
# File lib/custom_attributes/search_query.rb, line 239
def custom_query_scaffold(query, field_slug, filter = false)
  condition = { match: { 'custom_field_values.value' => query } }
  condition = { term: { 'custom_field_values.value.raw' => query } } if filter

  {
    nested: {
      path: 'custom_field_values',
      query: {
        bool: {
          must: [
            condition,
            {
              term: { 'custom_field_values.custom_field_id' => resolve_custom_field_id(field_slug) }
            }
          ]
        }
      }
    }
  }
end
custom_value_queries() click to toggle source
# File lib/custom_attributes/search_query.rb, line 128
def custom_value_queries
  return [] if filter_only_custom_fields(field_list).count.zero?

  filter_only_custom_fields(field_list).map do |field_slug, field|
    custom_query_scaffold(field.to_query_hash, field_slug) unless field.to_query_hash.empty?
  end.compact
end
filter_hash_to_term_array(filter_list, delimiter = '') click to toggle source
# File lib/custom_attributes/search_query.rb, line 172
def filter_hash_to_term_array(filter_list, delimiter = '')
  hash_to_array(filter_list) do |type, field_slug, field_data|
    field_data = field_data.split(delimiter).map(&:strip) if !delimiter.empty? && !field_data.is_a?(Array)

    if type == :custom_fields
      if field_data.is_a? Array
        field_data.map { |fd| custom_query_scaffold(fd, field_slug, true) }
      else
        custom_query_scaffold(field_data, field_slug, true)
      end
    else
      key = 'term'
      key = key.pluralize if field_data.is_a? Array

      { key.to_sym => { field_slug.to_s => field_data } }
    end
  end
end
filter_only_custom_fields(fields) click to toggle source
# File lib/custom_attributes/search_query.rb, line 209
def filter_only_custom_fields(fields)
  return {} if fields[:custom_fields].nil?

  Hash[fields[:custom_fields].map { |k, v| [k, CustomAttributes::SearchQueryField.new(v, defaults)] }]
end
filter_out_custom_fields(fields) click to toggle source
# File lib/custom_attributes/search_query.rb, line 203
def filter_out_custom_fields(fields)
  return {} if fields[:fields].nil?

  Hash[fields[:fields].map { |k, v| [k, CustomAttributes::SearchQueryField.new(v, defaults)] }]
end
filter_term_array() click to toggle source
# File lib/custom_attributes/search_query.rb, line 191
def filter_term_array
  return filter_hash_to_term_array(filter_by) if filter_or.empty?

  filter_hash = { minimum_should_match: 1 }
  filter_hash[:must] = filter_hash_to_term_array(filter_by, filter_by_delimiter) unless filter_by.empty?
  filter_hash[:should] = filter_hash_to_term_array(filter_or, filter_or_delimiter) unless filter_or.empty?

  [{
    bool: filter_hash
  }]
end
find_custom_field_by_slug(field_slug) click to toggle source
# File lib/custom_attributes/search_query.rb, line 219
def find_custom_field_by_slug(field_slug)
  customizable.available_custom_fields.find { |cf| cf.slug == field_slug.to_s } || raise('Field not found')
end
hash_to_array(field_list) { |type, field_slug, field_data| ... } click to toggle source
# File lib/custom_attributes/search_query.rb, line 223
def hash_to_array(field_list)
  field_list.map do |type, fields|
    fields.map do |field_slug, field_data|
      yield(type, field_slug, field_data)
    end
  end.flatten.compact
end
match_any_decorator(query_array) click to toggle source
# File lib/custom_attributes/search_query.rb, line 231
def match_any_decorator(query_array)
  if !match_any?
    { must: query_array }
  else
    { should: query_array, minimum_should_match: 1 }
  end
end
model_field_queries() click to toggle source
# File lib/custom_attributes/search_query.rb, line 136
def model_field_queries
  return [] if filter_out_custom_fields(field_list).count.zero?

  queries = filter_out_custom_fields(field_list).map do |field_slug, field|
    { match: { field_slug => field.to_query_hash } } unless field.to_query_hash.empty?
  end.compact

  return [] if queries.empty?

  [{
    bool: {
      should: queries,
      minimum_should_match: 1
    }
  }]
end
resolve_custom_field_id(field_slug) click to toggle source
# File lib/custom_attributes/search_query.rb, line 215
def resolve_custom_field_id(field_slug)
  find_custom_field_by_slug(field_slug).try(:id) || raise('Field id not found')
end
sort_hash_to_array() click to toggle source
# File lib/custom_attributes/search_query.rb, line 153
def sort_hash_to_array
  hash_to_array(sort_by) do |type, field_slug, field_data|
    if type == :custom_fields
      next unless find_custom_field_by_slug(field_slug).sortable
      {
        'custom_field_values.value.raw' => {
          order: field_data || 'asc',
          nested_path: 'custom_field_values',
          nested_filter: {
            term: { 'custom_field_values.custom_field_id' => resolve_custom_field_id(field_slug) }
          }
        }
      }
    else
      { field_slug.to_s => { order: field_data } }
    end
  end
end
subquery() click to toggle source
# File lib/custom_attributes/search_query.rb, line 87
def subquery
  filter = filter_term_array + [{ term: { visible_in_search: true } }]

  # match all documents if no particular query isset
  if query == '*' && field_list.empty?
    return {
      bool: {
        must: [
          {
            match_all: {}
          }
        ],
        filter: filter
      }
    }
  end


  {
    bool: {
      filter: filter
    }.merge(match_any_decorator(collect_queries))
  }
end