lib/europeana/blacklight/response/facets.rb
# frozen_string_literal: true
module Europeana
module Blacklight
class Response
##
# Facets for {Europeana::Blacklight::Response}
#
# Based on {Blacklight::SolrResponse::Facets} v5.10.2
module Facets
require 'ostruct'
# represents a facet value; which is a field value and its hit count
class FacetItem < OpenStruct
def initialize(*args)
options = args.extract_options!
# Backwards-compat method signature
value = args.shift
hits = args.shift
options[:value] = value if value
options[:hits] = hits if hits
super(options)
end
def label
super || value
end
def as_json(props = nil)
table.as_json(props)
end
end
# represents a facet; which is a field and its values
class FacetField
attr_reader :name, :items
def initialize(name, items, options = {})
@name = name
@items = items
@options = options
end
def limit
@options[:limit] || default_limit
end
def offset
@options[:offset] || default_offset
end
# Expected by {Blacklight::Facet#facet_paginator}
def prefix; end
def sort
# Europeana API does not support facet sorting
nil
end
private
# @see http://labs.europeana.eu/api/search/#offset-and-limit-of-facets
def default_limit
100
end
# @see http://labs.europeana.eu/api/search/#offset-and-limit-of-facets
def default_offset
0
end
end
def aggregations
@aggregations ||= {}.merge(facet_field_aggregations).merge(facet_query_aggregations)
end
def facet_fields
@facet_fields ||= self['facets'] || []
end
def facet_queries
@facet_queries ||= self['facet_queries'] || {}
end
private
##
# Convert API's facets response into a hash of
# {Europeana::Blacklight::Response::Facet::FacetField} objects
def facet_field_aggregations
facet_fields.each_with_object({}) do |facet, hash|
facet_field_name = facet['name']
items = facet['fields'].map do |value|
FacetItem.new(value: value['label'], hits: value['count'])
end
if blacklight_config && blacklight_config.facet_fields[facet_field_name]
if blacklight_config.facet_fields[facet_field_name].group.present?
items = grouped_facet_field_items(facet_field_name, items)
end
end
hash[facet_field_name] = FacetField.new(facet_field_name, items, facet_field_aggregation_options(facet_field_name))
next unless blacklight_config && !blacklight_config.facet_fields[facet_field_name]
# alias all the possible blacklight config names..
blacklight_config.facet_fields.select { |_k, v| v.field == facet_field_name }.each do |key, _|
hash[key] = hash[facet_field_name]
end
end
end
def grouped_facet_field_items(facet_field_name, items)
groups = {}
items.each do |item|
item_group = blacklight_config.facet_fields[facet_field_name].group.call(item)
if groups.key?(item_group)
groups[item_group].hits += item.hits
else
groups[item_group] = FacetItem.new(item_group, item.hits)
end
end
groups.values.sort_by { |item| -item.hits }
end
def facet_field_aggregation_options(name)
options = {}
if params[:"f.#{name}.facet.limit"]
options[:limit] = params[:"f.#{name}.facet.limit"].to_i
elsif params[:'facet.limit']
options[:limit] = params[:'facet.limit'].to_i
end
if params[:"f.#{name}.facet.offset"]
options[:offset] = params[:"f.#{name}.facet.offset"].to_i
elsif params[:'facet.offset']
options[:offset] = params[:'facet.offset'].to_i
end
options
end
##
# Aggregate API's facet_query response into the virtual facet fields
# defined in the blacklight configuration
def facet_query_aggregations
return {} unless blacklight_config
query_facet_fields = blacklight_config.facet_fields.select { |_k, v| v.query }
query_facet_fields.each_with_object({}) do |(field_name, facet_field), hash|
facet_query_params = facet_field.query.map { |_k, v| v[:fq] }
response_facet_queries = facet_queries.dup
response_facet_queries.select! { |k, _hits| facet_query_params.include?(k) }
response_facet_queries.reject! { |_k, hits| hits == 0 }
items = response_facet_queries.map do |value, hits|
salient_fields = facet_field.query.select { |_k, v| v[:fq] == value }
key = ((salient_fields.keys if salient_fields.respond_to? :keys) || salient_fields.first).first
FacetItem.new(value: key, hits: hits, label: facet_field.query[key][:label])
end
hash[field_name] = FacetField.new(field_name, items)
end
end
end
end
end
end