131 lines
3.3 KiB
Ruby
131 lines
3.3 KiB
Ruby
|
|
class QueryResult
|
||
|
|
|
||
|
|
include Enumerable
|
||
|
|
|
||
|
|
attr_reader :klass, :response, :current_page, :per_page, :error, :notice
|
||
|
|
|
||
|
|
def initialize(model_name, response, options={})
|
||
|
|
@klass = model_name.classify.constantize
|
||
|
|
@response = response
|
||
|
|
@current_page = options[:page] || 1
|
||
|
|
@per_page = options[:per_page] || ArchiveConfig.ITEMS_PER_PAGE
|
||
|
|
@error = response[:error]
|
||
|
|
@notice = max_search_results_notice
|
||
|
|
end
|
||
|
|
|
||
|
|
def hits
|
||
|
|
response.dig('hits', 'hits')
|
||
|
|
end
|
||
|
|
|
||
|
|
def items
|
||
|
|
return [] if response[:error]
|
||
|
|
if @items.nil?
|
||
|
|
@items = klass.load_from_elasticsearch(hits, scopes: @scopes)
|
||
|
|
end
|
||
|
|
@items
|
||
|
|
end
|
||
|
|
|
||
|
|
def scope(*args)
|
||
|
|
@scopes ||= []
|
||
|
|
@scopes += args
|
||
|
|
@items = nil # reset the items in case we already loaded them
|
||
|
|
self # for chaining
|
||
|
|
end
|
||
|
|
|
||
|
|
def each(&block)
|
||
|
|
items.each(&block)
|
||
|
|
end
|
||
|
|
|
||
|
|
def empty?
|
||
|
|
items.empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def size
|
||
|
|
items.size
|
||
|
|
end
|
||
|
|
alias :length :size
|
||
|
|
|
||
|
|
def [](index)
|
||
|
|
items[index]
|
||
|
|
end
|
||
|
|
|
||
|
|
def to_ary
|
||
|
|
items
|
||
|
|
end
|
||
|
|
|
||
|
|
def load_tag_facets(type, info)
|
||
|
|
@facets[type] = []
|
||
|
|
buckets = info["buckets"]
|
||
|
|
ids = buckets.map { |result| result['key'] }
|
||
|
|
tags = Tag.where(id: ids).group_by(&:id)
|
||
|
|
buckets.each do |facet|
|
||
|
|
unless tags[facet['key'].to_i].blank?
|
||
|
|
@facets[type] << QueryFacet.new(facet['key'], tags[facet['key'].to_i].first.name, facet['doc_count'])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def load_collection_facets(info)
|
||
|
|
@facets["collections"] = []
|
||
|
|
buckets = info["buckets"]
|
||
|
|
ids = buckets.map { |result| result['key'] }
|
||
|
|
collections = Collection.where(id: ids).group_by(&:id)
|
||
|
|
buckets.each do |facet|
|
||
|
|
unless collections[facet['key'].to_i].blank?
|
||
|
|
@facets["collections"] << QueryFacet.new(facet['key'], collections[facet['key'].to_i].first.title, facet['doc_count'])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def load_facets(aggregations)
|
||
|
|
aggregations.each_pair do |term, results|
|
||
|
|
if Tag::TYPES.include?(term.classify) || term == "tag"
|
||
|
|
load_tag_facets(term, results)
|
||
|
|
elsif term == "collections"
|
||
|
|
load_collection_facets(results)
|
||
|
|
elsif term == "bookmarks"
|
||
|
|
load_facets(results["filtered_bookmarks"])
|
||
|
|
elsif term == "bookmarkable"
|
||
|
|
load_facets(results)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def facets
|
||
|
|
return if response["aggregations"].nil?
|
||
|
|
|
||
|
|
if @facets.nil?
|
||
|
|
@facets = {}
|
||
|
|
load_facets(response["aggregations"])
|
||
|
|
end
|
||
|
|
|
||
|
|
@facets
|
||
|
|
end
|
||
|
|
|
||
|
|
def total_pages
|
||
|
|
(total_entries / per_page.to_f).ceil rescue 0
|
||
|
|
end
|
||
|
|
|
||
|
|
# For pagination / fetching results.
|
||
|
|
def total_entries
|
||
|
|
[unlimited_total_entries, ArchiveConfig.MAX_SEARCH_RESULTS].min
|
||
|
|
end
|
||
|
|
|
||
|
|
def unlimited_total_entries
|
||
|
|
response.dig('hits', 'total', 'value') || 0
|
||
|
|
end
|
||
|
|
|
||
|
|
def offset
|
||
|
|
(current_page * per_page) - per_page
|
||
|
|
end
|
||
|
|
|
||
|
|
def max_search_results_notice
|
||
|
|
# if we're on the last page of search results AND there are more results than we can show
|
||
|
|
return unless current_page >= total_pages && unlimited_total_entries > total_entries
|
||
|
|
ActionController::Base.helpers.ts("Displaying %{displayed} results out of %{total}. Please use the filters or edit your search to customize this list further.",
|
||
|
|
displayed: total_entries,
|
||
|
|
total: unlimited_total_entries
|
||
|
|
).html_safe
|
||
|
|
end
|
||
|
|
end
|